<!-- eslint-disable vue/no-v-text-v-html-on-component -->
<template>
  <view style="position: relative;">
    <view
      v-if="type === '2'"
      class="verify-img-out"
      :style="{height: (parseInt(imgSize.height) + vSpace) + 'px'}"
    >
      <view
        class="verify-img-panel"
        :style="{width: imgSize.width, height: imgSize.height,}"
      >
        <image
          :src="backImgBase?('data:image/png;base64,'+backImgBase):defaultImg"
          alt=""
          style="width:100%;height:100%;display:block"
        />
        <view
          v-show="showRefresh"
          class="verify-refresh"
          @click="refresh"
        >
          <text class="iconfont icon-refresh" />
        </view>
        <transition name="tips">
          <text
            v-if="tipWords"
            class="verify-tips"
            :class="passFalg ? 'suc-bg':'err-bg'"
          >
            {{ tipWords }}
          </text>
        </transition>
      </view>
    </view>

    <!-- 公共部分 -->
    <view
      class="verify-bar-area"
      :style="{width: imgSize.width, height: '36px', 'line-height':'36px'}"
    >
      <text
        class="verify-msg"
        v-text="text"
      />
      <view
        class="verify-left-bar"
        :style="{width: leftBarWidth?leftBarWidth:'36px', height: '36px', 'border-color': leftBarBorderColor, transaction: transitionWidth}"
      >
        <text
          class="verify-msg"
          v-text="finishText"
        />
        <view
          class="verify-move-block"
          :style="{width:'36px', height: '36px', 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}"
          @touchstart="start"
          @touchend="end"
          @touchmove="move"
          @mousedown="touchHandler"
        >
          <text
            :class="['verify-icon iconfont', iconClass]"
            :style="{color: iconColor}"
          />
          <view
            v-if="type === '2'"
            class="verify-sub-block"
            :style="{'width':Math.floor(parseInt(imgSize.width)*47/310)+ 'px' , 'height': imgSize.height, 'top':'-' + (parseInt(imgSize.height) + vSpace) + 'px',
            }"
          >
            <image
              :src="'data:image/png;base64,'+blockBackImgBase"
              alt=""
              style="width:100%;height:100%;display:block"
            />
          </view>
        </view>
      </view>
    </view>
  </view>
</template>
<script setup>
/**
* VerifySlide
* @description 滑块
* */
import { watch } from 'vue'
import { aesEncrypt } from '../utils/ase.js'
import { reqGet, reqCheck } from '../utils/request.js'

const emit = defineEmits(['success'])

const props = defineProps({
  captchaType: {
    type: String,
    default: '1'
  },
  type: {
    type: String,
    default: '1'
  },
  // 弹出式pop，固定fixed
  mode: {
    type: String,
    default: 'fixed'
  },
  vSpace: {
    type: Number,
    default: 15
  },
  explain: {
    type: String,
    default: '向右拖动滑块填充拼图'
  },
  imgSize: {
    type: Object,
    default () {
      return {
        width: '310px',
        height: '155px'
      }
    }
  },
  blockSize: {
    type: Object,
    default () {
      return {
        width: '50px',
        height: '50px'
      }
    }
  },
  barSize: {
    type: Object,
    default () {
      return {
        width: '100%',
        height: '40px'
      }
    }
  },
  defaultImg: {
    type: String,
    default: ''
  }
})
const { proxy } = getCurrentInstance()
let secretKey = '' // 后端返回的加密秘钥 字段
const passFalg = ref(false) // 请求通过与否
const backImgBase = ref('') // 验证码背景图片
const blockBackImgBase = ref('') // 验证滑块的背景图片
let backToken = '' // 后端返回的唯一token值
let startMoveTime = '' // 移动开始的时间
let endMovetime = '' // 移动结束的时间
// eslint-disable-next-line no-unused-vars
const tipsBackColor = ref('') // 提示词的北京颜色
const tipWords = ref('')
const text = ref('')
const finishText = ref('')
// eslint-disable-next-line no-unused-vars
const setSize = reactive({
  imgHeight: 0,
  imgWidth: 0,
  barHeight: 0,
  barWidth: 0
})
// eslint-disable-next-line no-unused-vars
const top = ref(0)
// eslint-disable-next-line no-unused-vars
const left = ref(0)
const moveBlockLeft = ref(undefined)
const leftBarWidth = ref(undefined)
// 移动中样式
const moveBlockBackgroundColor = ref('#082BA6')
const leftBarBorderColor = ref('#ddd')
const iconColor = ref(undefined)
const iconClass = ref('icon-right')
let status = false // 鼠标状态
let isEnd = false // 是够验证完成
const showRefresh = ref(true)
const transitionLeft = ref('')
const transitionWidth = ref('')

// 鼠标按下
const start = (e) => {
  startMoveTime = new Date().getTime() // 开始滑动的时间
  if (isEnd == false) {
    text.value = ''
    moveBlockBackgroundColor.value = '#082BA6'
    leftBarBorderColor.value = '#082BA6'
    iconColor.value = '#fff'
    e.stopPropagation()
    status = true
  }
}
// 鼠标移动
const move = (e) => {
  const query = uni.createSelectorQuery().in(proxy)
  const barArea = query.select('.verify-bar-area')
  let barAreaLeft, barAreaOffsetWidth
  barArea.boundingClientRect(data => {
    barAreaLeft = Math.ceil(data.left)
    barAreaOffsetWidth = Math.ceil(data.width)

    if (status && isEnd == false) {
      let x
      if (!e.touches) { // 兼容移动端
        x = Math.ceil(e.clientX)
      } else { // 兼容PC端
        x = Math.ceil(e.touches[0].pageX)
      }
      let _moveBlockLeft = x - barAreaLeft // 小方块相对于父元素的left值
      if (props.type !== '1') { // 图片滑动
        if (_moveBlockLeft >= barAreaOffsetWidth - parseInt(parseInt(props.blockSize.width) / 2) - 2) {
          _moveBlockLeft = barAreaOffsetWidth - parseInt(parseInt(props.blockSize.width) / 2) - 2
        }
      }

      if (_moveBlockLeft <= 0) {
        _moveBlockLeft = parseInt(parseInt(props.blockSize.width) / 2)
      }

      // 拖动后小方块的left值
      moveBlockLeft.value = (_moveBlockLeft - parseInt(parseInt(props.blockSize.width) / 2)) + 'px'
      leftBarWidth.value = (_moveBlockLeft - parseInt(parseInt(props.blockSize.width) / 2)) + 'px'
    }
  }).exec()
}

// 鼠标松开
const end = () => {
  endMovetime = new Date().getTime()
  // 判断是否重合
  if (status && isEnd == false) {
    if (props.type !== '1') { // 图片滑动
      let moveLeftDistance = parseInt((moveBlockLeft.value || '').replace('px', ''))
      moveLeftDistance = moveLeftDistance * 310 / parseInt(props.imgSize.width)
      const captchaVerification = secretKey ? aesEncrypt(backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKey) : backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 })
      const data = {
        captchaType: props.captchaType,
        pointJson: secretKey ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), secretKey) : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
        token: backToken
      }
      const params = {
        data
      }
      reqCheck(params).then(({ data: res }) => {
        if (res.repCode == '0000') {
          moveBlockBackgroundColor.value = '#5cb85c'
          leftBarBorderColor.value = '#5cb85c'
          iconColor.value = '#fff'
          iconClass.value = 'icon-check'
          showRefresh.value = true
          isEnd = true
          setTimeout(() => {
            if (props.mode == 'pop') {
              proxy.$parent.clickShow = false
            }
            refresh()
          }, 1500)
          passFalg.value = true
          tipWords.value = `${((endMovetime - startMoveTime) / 1000).toFixed(2)}s验证成功`
          setTimeout(() => {
            tipWords.value = ''
            emit('success', { captchaVerification })
          }, 1000)
        } else {
          moveBlockBackgroundColor.value = '#d9534f'
          leftBarBorderColor.value = '#d9534f'
          iconColor.value = '#fff'
          iconClass.value = 'icon-close'
          passFalg.value = false
          setTimeout(() => {
            refresh()
          }, 1000)
          proxy.$parent.$emit('error', proxy)
          tipWords.value = '验证失败'
          setTimeout(() => {
            tipWords.value = ''
          }, 1000)
        }
      })
    }
    status = false
  }
}
const refresh = () => {
  showRefresh.value = true
  finishText.value = ''
  transitionLeft.value = 'left .3s'
  moveBlockLeft.value = 0
  leftBarWidth.value = false
  transitionWidth.value = 'width .3s'
  leftBarBorderColor.value = '#082BA6'
  moveBlockBackgroundColor.value = '#082BA6'
  iconColor.value = '#000'
  iconClass.value = 'icon-right'
  getPictrue()
  isEnd = false
  setTimeout(() => {
    transitionWidth.value = ''
    transitionLeft.value = ''
    text.value = props.explain
  }, 300)
}

// 获取left值
// eslint-disable-next-line no-unused-vars
const getLeft = (node) => {
  let leftValue = 0
  while (node) {
    leftValue += node.offsetLeft
    node = node.offsetParent
  }
  const finalvalue = leftValue
  return finalvalue
}

// 请求背景图片和验证图片
const getPictrue = () => {
  const data = {
    data: {
      captchaType: props.captchaType,
      clientUid: uni.getStorageSync('bbcSlider'),
      ts: Date.now() // 现在的时间戳
    },
    callBack: res => {
      if (res.repCode == '0000') {
        backImgBase.value = res.repData.originalImageBase64
        blockBackImgBase.value = res.repData.jigsawImageBase64
        backToken = res.repData.token
        secretKey = res.repData.secretKey
      } else {
        tipWords.value = res.repMsg
      }
      // 判断接口请求次数是否失效
      if (res.repCode == '6201') {
        backImgBase.value = null
        blockBackImgBase.value = null
      }
    }
  }
  reqGet(data).then(({ data: res }) => {
    if (res.repCode == '0000') {
      backImgBase.value = res.repData.originalImageBase64
      blockBackImgBase.value = res.repData.jigsawImageBase64
      backToken = res.repData.token
      secretKey = res.repData.secretKey
    } else {
      tipWords.value = res.repMsg
    }
    // 判断接口请求次数是否失效
    if (res.repCode == '6201') {
      backImgBase.value = null
      blockBackImgBase.value = null
    }
  })
}

/**
 * 鼠标点击处理
 * 因为
 * 在一些浏览器的PC端比如火狐，需要启用触摸模拟才生效
 */
const touchHandler = (e) => {
  // #ifdef H5
  if (navigator.userAgent.indexOf('Mobile') === -1) {
    start(e)
  }
  // #endif
}
const init = () => {
  text.value = props.explain
  getPictrue()
  nextTick(() => {
    proxy.$parent.$emit('ready', proxy)
  })
}
watch(() => props.type, () => {
  init()
}, {
  immediate: true
})
</script>
<!-- eslint-disable vue-scoped-css/no-unused-selector -->
<style scoped>
.verifybox{
  position: relative;
  box-sizing: border-box;
  border-radius: 2px;
  border: 1px solid #e4e7eb;
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0,0,0,.3);
  left: 50%;
  top:50%;
  transform: translate(-50%,-50%);
}
.verifybox-top{
  padding: 0 15px;
  height: 50px;
  line-height: 50px;
  text-align: left;
  font-size: 16px;
  color: #45494c;
  border-bottom: 1px solid #e4e7eb;
  box-sizing: border-box;
}
.verifybox-bottom{
  box-sizing: border-box;
}
.verifybox-close{
  position: absolute;
  top: 13px;
  right: 9px;
  width: 24px;
  height: 24px;
  text-align: center;
  cursor: pointer;
}
.mask{
  position: fixed;
  top: 0;
  left:0;
  z-index: 1001;
  width: 100%;
  height: 100vh;
  background: rgba(0,0,0,.3);
  transition: all .5s;
}
.verify-tips{
  position: absolute;
  left: 0px;
  bottom:0px;
  width: 100%;
  height: 30px;
  background-color:rgb(231, 27, 27,.5);
  line-height:30px;
  color: #fff;
  font-size: 26rpx;
  text-indent: 10rpx;
}
.suc-bg{
  background-color:rgba(92, 184, 92,.5);
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
}

.err-bg{
  background-color:rgba(217, 83, 79,.5);
  filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
}

.tips-enter,.tips-leave-to{
  bottom: -30px;
}
.tips-enter-active,.tips-leave-active{
transition: bottom .5s;
}
/* ---------------------------- */
/*常规验证码*/
.verify-code {
font-size: 20px;
  text-align: center;
  cursor: pointer;
  margin-bottom: 5px;
  border: 1px solid #ddd;
}

.cerify-code-panel {
  height: 100%;
  overflow: hidden;
}

.verify-code-area {
  float: left;
}

.verify-input-area {
  float: left;
  width: 60%;
  padding-right: 10px;
}

.verify-change-area {
  line-height: 30px;
  float: left;
}

.varify-input-code {
  display: inline-block;
  width: 100%;
  height: 25px;
}

.verify-change-code {
  color: #337AB7;
  cursor: pointer;
}

.verify-btn {
  width: 200px;
  height: 30px;
  background-color: #337AB7;
  color: #FFFFFF;
  border: none;
  margin-top: 10px;
}

/*滑动验证码*/
.verify-bar-area {
  position: relative;
  background: #FFFFFF;
  text-align: center;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.verify-bar-area .verify-move-block {
  position: absolute;
  top: 0px;
  left: 0;
  background: #fff;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  box-shadow: 0 0 2px #888888;
  -webkit-border-radius: 1px;
}

.verify-bar-area .verify-move-block:hover {
  background-color: #337ab7;
  color: #FFFFFF;
}

.verify-bar-area .verify-left-bar {
  position: absolute;
  top: -1px;
  left: -1px;
  background: #f0fff0;
  cursor: pointer;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border: 1px solid #ddd;
}

.verify-img-panel {
  margin: 0;
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  border-top: 1px solid #ddd;
  border-bottom: 1px solid #ddd;
  border-radius: 3px;
  position: relative;
}

.verify-img-panel .verify-refresh {
  width: 25px;
  height: 25px;
  text-align: center;
  padding: 5px;
  cursor: pointer;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
}

.verify-img-panel .icon-refresh {
  font-size: 20px;
  color: #fff;
}

.verify-img-panel .verify-gap {
  background-color: #fff;
  position: relative;
  z-index: 2;
  border: 1px solid #fff;
}

.verify-bar-area .verify-move-block .verify-sub-block {
  position: absolute;
  text-align: center;
  z-index: 3;
  /* border: 1px solid #fff; */
}

.verify-bar-area .verify-move-block .verify-icon {
  font-size: 18px;
}

.verify-bar-area .verify-msg {
  z-index: 3;
  color: #333333;
  font-size: 26rpx;
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-check:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}

.icon-close:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}

.icon-right:before {
  content: " ";
  display: block;
  width: 22px;
  height: 22px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-size: cover;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}

.icon-refresh:before {
  content: " ";
  display: block;
  width: 16px;
  height: 16px;
  position: absolute;
  margin: auto;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  background-image: url("");
  background-size: contain;
}
</style>
